package com.smartplatform.operlog;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.smartplatform.exception.BaseException;
import com.smartplatform.mapper.SysOperLogMapper;
import com.smartplatform.operlog.annotations.LogAnnotation;
import com.smartplatform.pojo.MyBaseUser;
import com.smartplatform.pojo.SysOperLog;
import com.smartplatform.utils.RequestUtil;
import com.smartplatform.utils.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author 咕唧
 * @Date 2022/6/8 19:09
 * @Version 1.0
 */
@Aspect//aop注解
@Component
public class LogAdvice {

    private ObjectMapper objectMapper;

    private ThreadPoolExecutor threadPoolExecutor;

    private SysOperLogMapper sysOperLogMapper;

    @Autowired
    public void setSysOperLogMapper(SysOperLogMapper sysOperLogMapper) {
        this.sysOperLogMapper = sysOperLogMapper;
    }

    @Autowired
    public void setThreadPoolExecutor(ThreadPoolExecutor threadPoolExecutor) {
        this.threadPoolExecutor = threadPoolExecutor;
    }

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    //声明切入点表达式，拦截的是带有我们指定某个注解的方法
    @Pointcut("@annotation(com.smartplatform.operlog.annotations.LogAnnotation)")
    public void pointcut() {
    }

    @AfterReturning(value = "pointcut()", returning = "result")
    public void after(JoinPoint joinPoint, Object result) {
        SysOperLog sysOperLog = new SysOperLog();
        //当前方法时没有异常方法，能到达这个方法状态必然是成功的
        sysOperLog.setStatus(1L);
        sysOperLog.setErrorMsg("200 ok");
        //返回结果的json
        try {
            String resultJson = objectMapper.writeValueAsString(result);
            sysOperLog.setJsonResult(resultJson);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        //添加其他数据方法
        addLog(joinPoint, sysOperLog);
    }

    @AfterThrowing(pointcut = "pointcut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e) {
        SysOperLog sysOperLog = new SysOperLog();
        //当前方法时没有异常方法，能到达这个方法状态必然是成功的
        sysOperLog.setStatus(0L);
        if (e instanceof BaseException) {
            sysOperLog.setErrorMsg(((BaseException) e).getCode() + e.getMessage());
        } else {
            sysOperLog.setErrorMsg(e.getMessage());
        }
        addLog(joinPoint, sysOperLog);
    }

    public void addLog(JoinPoint joinPoint, SysOperLog sysOperLog) {
        //TODO 获取记录日志的相关信息
        MyBaseUser userInfo = SecurityUtils.getUserInfo(false);
        if (userInfo != null) {
            sysOperLog.setOperName(userInfo.getUsername());
        }
        //获取request对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //开启异步运行
        CompletableFuture.runAsync(() -> {
            //获取请求方式
            String requestMethod = request.getMethod();
            sysOperLog.setRequestMethod(requestMethod);
            //获取请求地址
            String requestURI = request.getRequestURI();
            sysOperLog.setOperUrl(requestURI);
            //获取ip
            String ip = RequestUtil.getRemoteHost(request);
            sysOperLog.setOperIp(ip);
            //获取操作系统
            Map<String, String> osAndBrowserInfo = RequestUtil.getOsAndBrowserInfo(request);
            //设置客户端
            String os = osAndBrowserInfo.get("os");
            switch (os) {
                case "Android":
                case "IPhone":
                    //设置来自于移动端
                    sysOperLog.setOperatorType(2L);
                    break;
                case "Windows":
                case "Mac":
                case "Unix":
                    //设置来自于PC端
                    sysOperLog.setOperatorType(1L);
                    break;
                default:
                    //设置来自于其他端
                    sysOperLog.setOperatorType(0L);
                    break;
            }
            //获取方法的名字
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            String methodName = signature.getName();
            sysOperLog.setMethod(methodName);
            //方法上有注解，需要获取注解上的数据
            Method method = signature.getMethod();
            LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
            if (logAnnotation!=null){
                String title = logAnnotation.title();
                long businessType = logAnnotation.businessType();
                sysOperLog.setTitle(title);
                sysOperLog.setBusinessType(businessType);
            }

            //获取请求的参数，参数都在方法当中
            Object[] args = joinPoint.getArgs();
            try {
                sysOperLog.setOperName(objectMapper.writeValueAsString(args));
            } catch (JsonProcessingException e) {
               throw new RuntimeException(e);
            }
            //操作时间
            Date operTime = new Date();
            sysOperLog.setOperTime(operTime);
            //获取地址
            String locationByIp = RequestUtil.getLocationByIp(ip);
            sysOperLog.setOperLocation(locationByIp);


            System.err.println(sysOperLog);

            //插入数据库
            sysOperLogMapper.insertOperLog(sysOperLog);

        }, threadPoolExecutor);



    }
}
